import { MusicNode } from '@/interface/music'

class Dispatcher{
    handlers: Array<any>
    constructor(){
        this.handlers = []
    }
    push(h: any){
        this.handlers.push(h)
    }
    emit() {
        this.handlers.forEach( h => {
            h()
        })
    }
}
class Player{
    audioCtx: AudioContext
    analyser: AnalyserNode
    playList: Array<MusicNode>
    playIndex: number
    emptyNode: MusicNode
    onPlay: Dispatcher
    onPause: Dispatcher
    onReady: Dispatcher
    onChange: Dispatcher
    constructor() {
        this.audioCtx = new AudioContext
        this.analyser = this.audioCtx.createAnalyser()
        this.playList = [],
        this.playIndex = 0,
        this.emptyNode = {
            info: null, //歌曲各种信息
            start: 0, //记录曲目开始的时间
            offset: 0, //开始位置偏移量
            source: null, // AudioBufferSourceNode 实例(控制播放音乐的)
            buffer: null, // 文件的buffer
          }
        this.onPlay = new Dispatcher()
        this.onPause = new Dispatcher()
        this.onReady = new Dispatcher()
        this.onChange = new Dispatcher()
    }
    getBuffer(source: ArrayBuffer){
        return new Promise((resolve, reject) => {
            this.audioCtx.decodeAudioData(source)
            .then(res => { resolve(res) },err => {reject(err)})
        })
    }
    async appendNode(info: any, source: ArrayBuffer){
        this.playList.push({
            info: info,
            start: 0,
            offset: 0,
            source: null,
            buffer: await this.getBuffer(source) as AudioBuffer
        })
        if(this.isEmpty){
            this.onReady.emit()
        }
    }
    play() {
        if(!this.playList.length || this.current.source){
            return
        }
        const source = this.audioCtx.createBufferSource()
        source.buffer = this.current.buffer as AudioBuffer
        source.onended = this.next.bind(this)
        source.connect(this.audioCtx.destination)
        source.start(0, this.current.offset)
        this.current.source = source
        this.current.start = this.audioCtx.currentTime
        this.onPlay.emit()
    }
    pause() {
        if(!this.playList.length || !this.current.source)
        return
        this.current.source.stop(0)
        this.current.source.disconnect()
        this.current.source.onended = null
        this.current.offset = this.position
        this.current.start = 0
        this.onPause.emit()
    }
    stop() {
        this.pause()
        this.current.offset = 0
    }
    prev() {
        this.stop()
        --this.playIndex
        if(this.playIndex < 0){
            this.playIndex = this.playList.length-1
        }
        this.play()
        if(this.playList.length > 1){
            this.onChange.emit()
        }

    }
    next() {
        this.stop()
        ++this.playIndex
        if (this.playIndex >= this.playList.length) {
          this.playIndex = 0
        }
        this.play()
        if (this.playList.length > 1) {
          this.onChange.emit()
        }
      }
    get isEmpty() {
        return this.current === this.emptyNode
    }
    get current() {
        return this.playList[this.playIndex] || this.emptyNode
    }
    get duration() {
        const duration = this.current.buffer.duration
        return this.current.buffer ? duration : 0.001
    }
    get position() {
        if(!this.playList.length)
        return 0
        const t = this.current.offset + this.current.start === null ? 0: (this.audioCtx.currentTime - this.current.start)
        console.log(t)
        return t
    }
    set position(rate: number) {
        if(!this.playList.length)
        return
        this.pause()
        this.current.offset = this.duration * rate
        this.play()
    }
}
export const player = new Player()